<?php


namespace App\Event;


use App\Actor\ChatActor;
use App\Actor\ChatManager;
use App\Crontab\TestCrontab;
use App\Parser\WebSocketParser;
use EasySwoole\Actor\Actor;
use EasySwoole\Actor\Exception\InvalidActor;
use EasySwoole\Component\Singleton;
use EasySwoole\EasySwoole\Config;
use EasySwoole\EasySwoole\Crontab\Crontab;
use EasySwoole\EasySwoole\Logger;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\FileWatcher\FileWatcher;
use EasySwoole\FileWatcher\WatchRule;
use EasySwoole\ORM\DbManager;
use EasySwoole\Pool\Exception\Exception;
use EasySwoole\Redis\Config\RedisConfig;
use EasySwoole\RedisPool\RedisPool;
use EasySwoole\RedisPool\RedisPoolException;
use EasySwoole\Socket\Bean\Response;
use EasySwoole\Socket\Client\WebSocket;
use EasySwoole\Socket\Dispatcher;
use Swoole\Http\Request;
use Swoole\Server;
use Swoole\Websocket\Frame;

/**
 * 注册类（只能用户EasySoleEvent类的mainServerCreate方法中）
 * Class MainServerCreate
 * @package App\Event
 */
class MainServerCreate
{
    use Singleton;

    /**
     * @throws \EasySwoole\RedisPool\Exception\Exception
     * @throws Exception
     * @throws \EasySwoole\Socket\Exception\Exception
     * @throws RedisPoolException
     * @throws InvalidActor
     */
    public function initialize(EventRegister $register): void
    {
        $register->add($register::onWorkerStart, function () {
            $this->onWorkerStart();
        });

        // 注册redis
        $this->redis();
        // 热重载监视器
        $this->hotReload();
        // 注册websocket
        $this->websocket($register);
        // Crontab
        $this->crontab();

        $this->actor();
    }

    private function crontab(){
        Crontab::getInstance()->addTask(TestCrontab::class);
    }

    private function onWorkerStart()
    {
        // ORM连接预加载
        DbManager::getInstance()->getConnection()->__getClientPool()->keepMin();
    }

    /**
     * @throws \EasySwoole\Socket\Exception\Exception
     * @throws \Exception
     */
    /**
     * @throws \EasySwoole\Socket\Exception\Exception
     * @throws \Exception
     */
    private function websocket(EventRegister $register){
        $config = new \EasySwoole\Socket\Config();
        $config->setType($config::WEB_SOCKET);
        $config->setParser(WebSocketParser::class);
        $dispatcher = new Dispatcher($config);

        ChatManager::tableInit();

        $config->setOnExceptionHandler(function (Server $server, \Throwable $throwable, string $raw, WebSocket $client, Response $response) {
            $response->setMessage('system error!');
            $response->setStatus($response::STATUS_RESPONSE_AND_CLOSE);
        });

        // 自定义握手
        $websocketEvent = new WebSocketEvent();
        $register->set(EventRegister::onHandShake, function (Request $request, \Swoole\Http\Response $response) use ($websocketEvent) {
            $websocketEvent->onHandShake($request, $response);
        });

        $register->set($register::onMessage, function (\Swoole\Websocket\Server $server, Frame $frame) use ($dispatcher) {
            $dispatcher->dispatch($server, $frame->data, $frame);
        });
    }

    /**
     * 注册redis
     * @throws Exception
     * @throws \EasySwoole\RedisPool\Exception\Exception
     * @throws RedisPoolException
     */
    private function redis(): void
    {
        $redisConfig = new RedisConfig(Config::getInstance()->getConf('redis'));
        $redisPoolConfig = RedisPool::getInstance()->register($redisConfig, 'redis');
        //配置连接池连接数
        $redisPoolConfig->setMinObjectNum(5);
        $redisPoolConfig->setMaxObjectNum(20);
    }

    /**
     * 热重载监视器
     */
    private function hotReload(): void
    {
        $watcher = new FileWatcher();
        $rule = new WatchRule(EASYSWOOLE_ROOT . "/App"); // 设置监控规则和监控目录
        $watcher->addRule($rule);
        $watcher->setOnChange(function () {
            Logger::getInstance()->info('file change ,reload!!!');
            ServerManager::getInstance()->getSwooleServer()->reload();
        });
        $watcher->attachServer(ServerManager::getInstance()->getSwooleServer());
    }

    /**
     * @throws InvalidActor
     */
    private function actor()
    {
        // 注册Actor管理器
        $server = ServerManager::getInstance()->getSwooleServer();
        Actor::getInstance()->register(ChatActor::class);


        Actor::getInstance()->setTempDir(EASYSWOOLE_TEMP_DIR)
            ->setListenAddress('0.0.0.0')->setListenPort('9987')->attachServer($server);

    }
}